
/**
 *Clase que representa el problema del puzzle de 8
 *
 */

package Problemas;

import Busquedas.Estado;


public class Puzzle8 extends Problema {
	
	int[][] matriz;
	
	/**
	 * Constructora de clase.
	 */
	public Puzzle8(){
		int[] paramInicial = {2,8,3,1,6,4,7,0,5};
		int[] paramObjetivo = {1,2,3,8,0,4,7,6,5};
		Estado inicial = new Estado(paramInicial);
		Estado[] objetivo = new Estado[1];
		objetivo[0] = new Estado(paramObjetivo);		
		String [] nombresOperadores={"padre","arriba","abajo","izquierda","derecha"};
		int [] costeOperadores={1,1,1,1};		
		inicializa(inicial,objetivo,4,nombresOperadores,costeOperadores);
		matriz = new int[3][3];
	}

	//@Override
	/**
	 * Distancia Manhattan
	 */
	public int funcionHeuristica(Estado e) {
		int param[] = e.getParametros();
		int distanciaTotal = 0;
		int distancia;
		for (int i = 0; i < param.length; i++){
			//distancia desde donde está un número hasta donde debería estar
			if (param[i] !=0 ){//si no es el hueco
				distancia = distancia(i,posicion(param[i]));
				distanciaTotal = distanciaTotal+distancia;
			}
		}
		return distanciaTotal;
	}
	
	/**
	 * Metodo auxiliar para calcular la distancia de manahattan
	 * @param a coordenada x
	 * @param b coordenada y
	 * @return distancia
	 */
	public int distancia(int a,int b){
		int ia,ib,ja,jb;
		ia = a/3;
		ja = a%3;
		ib = b/3;
		jb = b%3;
		return (Math.abs(ia-ib)+Math.abs(ja-jb));		
	}
	
	/**
	 * Devuelve la posici�n en la que estar�an correctamente los n�meros
	 * @param n
	 * @return
	 */
	int posicion(int n){
		switch(n){
		case 1:	return 0;
		case 2: return 1;
		case 3: return 2;
		case 4: return 5;
		case 5: return 8;
		case 6: return 7;
		case 7: return 6;
		case 8: return 3;
		}
		return 4;
	}
	
	
	/**
	 * asigna los parametros del estado dado.
	 * @param e estado dado.
	 */
	public void asignaParametros(Estado e){
		int k = 0;
		int param[] = e.getParametros(); 
		for (int i = 0; i < 3; i++){
			for (int j = 0; j < 3; j++){
				matriz[i][j] = param[k];
				k++;
			}
		}
	}
	
	
	
	/**
	 * Convierte una matriz en un array
	 * @return array de elementos
	 */
	private int[] convierteMatrizEnArray(){
		int[] param = new int[9];
		int k = 0;
		for (int i = 0; i < 3; i++){
			for (int j = 0; j < 3; j++){
				param[k] = matriz[i][j];
				k++;
			}
		}
		return param;
	}
	
	
	/**
	 * Nos dice d�nde esta el hueco
	 * @param e estado actual
	 * @return indice del hueco
	 */
	private int indiceHueco(Estado e){
		int indice = -1;
		int i = 0;
		int[] param = e.getParametros();
		while (i < e.getNumParametros() && indice < 0){
			if (param[i] == 0){
				indice = i;
			}
			i++;
		}
		return indice;
	}
	
	/**
	 * 
	 *  Devolver� null si no se puede aplicar el operador
	 * @param actual estado en el que nos encontramos
	 * @return estado resultante
	 */
	public Estado arriba(Estado e){
		int hueco = indiceHueco(e);
		int i = hueco/3;
		int j = hueco%3;
		int aux;
		if (i-1 >= 0){
			aux = matriz[i-1][j];
			matriz[i-1][j] = matriz[i][j];
			matriz[i][j] = aux;
			return new Estado(convierteMatrizEnArray());			
		}
		return null;			
	}
	
	/**
	 * 
	 *  Devolver� null si no se puede aplicar el operador
	 * @param actual estado en el que nos encontramos
	 * @return estado resultante
	 */
	public Estado abajo(Estado e){
		int hueco = indiceHueco(e);
		int i = hueco/3;
		int j = hueco%3;
		int aux;
		if (i+1 < 3){
			aux = matriz[i+1][j];
			matriz[i+1][j] = matriz[i][j];
			matriz[i][j] = aux;
			return new Estado(convierteMatrizEnArray());			
		}
		return null;			
	}
	
	
	/**
	 * 
	 *  Devolver� null si no se puede aplicar el operador
	 * @param actual estado en el que nos encontramos
	 * @return estado resultante
	 */
	public Estado izquierda(Estado e){
		int hueco = indiceHueco(e);
		int i = hueco/3;
		int j = hueco%3;
		int aux;
		if (j-1 >= 0){
			aux = matriz[i][j-1];
			matriz[i][j-1] = matriz[i][j];
			matriz[i][j] = aux;
			return new Estado(convierteMatrizEnArray());			
		}
		return null;			
	}
	
	
	/**
	 * 
	 *  Devolver� null si no se puede aplicar el operador
	 * @param actual estado en el que nos encontramos
	 * @return estado resultante
	 */
	public Estado derecha(Estado e){
		int hueco = indiceHueco(e);
		int i = hueco/3;
		int j = hueco%3;
		int aux;
		if (j+1 < 3){
			aux = matriz[i][j+1];
			matriz[i][j+1] = matriz[i][j];
			matriz[i][j] = aux;
			return new Estado(convierteMatrizEnArray());			
		}
		return null;			
	}

	/* (non-Javadoc)
	 * @see Problema#aplicaOperador(Estado, int)
	 */
	//@Override
	public Estado aplicaOperador(Estado actual, int i) {
		asignaParametros(actual);
		Estado siguiente = null;
		switch(i){
		case 0:
			siguiente = arriba(actual);
			break;
		case 1:
			siguiente = abajo(actual);
			break;
		case 2:
			siguiente = izquierda(actual);
			break;
		case 3:
			siguiente = derecha(actual);
			break;
		}
		return siguiente;
	}

	/* (non-Javadoc)
	 * @see Problema#getOperadorInverso(int)
	 */
	//@Override
	public int getOperadorInverso(int op) {
		int inverso = -1;
		switch(op){
		case 0:
			inverso = 1;
			break;
		case 1:
			inverso = 0;
			break;
		case 2:
			inverso = 3;
			break;
		case 3:
			inverso = 2;
			break;
		}
		return inverso;
	}

      
	
}
